一个关于UART通信奇偶校验出错位的读取话题
某客户使用STM32F4系列芯片做产品开发,用到USART外设,将其配置在智能卡模式。USART配置为智能卡模式后,并开启了奇偶校验。
当MCU通过UART从卡端读取数据时,如果读到的数据发生奇偶校验错误,根据相关通信协议,USART硬件会自动在刚收到数据的结尾处强行拉低数据线一个时间段告知智能卡控制器,表示USART接收到的数据奇偶校验有错,期待数据重发。
他发现,当UART从智能卡接收数据遇到奇偶校验出错时,的确可以从硬件线路上观测到数据的重发。可他的软件接收代码里却没法分辨数据正误,也就是说不管是否发生校验错误,一律当作正确的数据接收了进来。他觉得甚为奇怪。
重点怀疑代码问题,查看其相关代码,他的数据接收流程大致是这样的:
先检测到USART_SR寄存器中的RXNE为1;然后从USAR_DR寄存器读取数据;再接着检测USART_SR寄存器中的校验出错位PE位是否为1,如果是1则丢弃刚才收到的数据。咋看上去,貌似没啥问题。
如果查看STM32相关芯片的参考手册就会发现,通过对USART_SR的读和接着对USART_DR的读操作序列会导致对RXNE和PE位的清零。
既然这样,按照该客户的做法,先读SR,然后读DR。这个连续操作之后已经就将RXNE和PE清零了,若再来读PE,永远读不到它为1的时候,即发现不了校验出错的情况,自然导致数据全部被当做正确的收纳了。
所以,他的接收代码需要稍微调整下,先检查到RXNE为1后,接着检查PE是否为1,根据PE是否为1 来决定从DR中读得数据的取舍并完成对PE和RXNE的清零。
STM32的寄存器中,尤其是那些状态寄存器的部分状态标志的置位和清零并不一定是简单地、对应地直接置1写0。比方有些寄存器位的清零是对相关寄存器位写1;有些寄存器位的清零则个软件操作序列。比方STM32F4/STM32F1系列中USART的PE位、ORE位就是通过软件操作序列实现清零。STM32产品线众多,即使相同外设的寄存器不同系列间的操作可能略有差异。比如这里谈到的USART的PE位、ORE位,在STM32F0系列里是可以通过软件对相关寄存器位写1达到对其清零的目的,此时无需软件操作序列。
当然,如果你使用ST官方的参考库函数的话,有些细节可能感受不到。开发过程中在具体使用到某些并不熟悉的寄存器位时,适当地核对下手册往往是个不错的举动。有时一个无意的想当然的举动可能会浪费很多时间和精力。
简单问题,分享出来,互为提醒。其实,开发过程中很多折腾人的地方往往就是些小细节。
=====================================
往期链接:
扫描或长按二维码可关注公众号